<?php
// +----------------------------------------------------------------------
// | UCToo [ Universal Convergence Technology ]
// +----------------------------------------------------------------------
// | Copyright (c) 2014-2021 https://www.uctoo.com All rights reserved.
// +----------------------------------------------------------------------
// | Licensed ( http://www.apache.org/licenses/LICENSE-2.0 )
// +----------------------------------------------------------------------
// | Author: Patrick <contact@uctoo.com>
// +----------------------------------------------------------------------

namespace uctoo\util\library;

use Firebase\JWT\JWT;
use uctoo\util\exception\TokenException;
use think\facade\Cache;

class Auth
{
    protected static $instance = null;

    protected static $accessToken;
    protected static $refreshToken;
    protected static $tokenExpire = 86400;
    protected $secretKey;

    protected $cachePrefix = 'serv.refresh_token.';


    const SECRET_KEY =  '';//TODO:从管理后台配置获取

    public function setSecretKey($secretKey){
        $this->secretKey = $secretKey;
        return $this;
    }

    protected function getSecretKey(){
        if(is_null($this->secretKey)){
            return self::SECRET_KEY;
        }

        return $this->secretKey;
    }

    public static function instance()
    {
        if(is_null(self::$instance)){
            self::$instance = new static();
        }

        return self::$instance;
    }

    public function setAccessToken($accessToken){
        self::$accessToken = $accessToken;
        return $this;
    }

    public function setRefreshToken($refreshToken){
        self::$refreshToken = $refreshToken;
        return $this;
    }

    public function checkUser(){
        return $this->tokenDecode(self::$accessToken);
    }

    public function TokenEncode($data,$expire = 0){
        $expire &&  self::$tokenExpire = $expire;
        $this->accessTokenEncode($data);
        $this->refreshTokenEncode($data);
        return ['access_token'=>self::$accessToken,'refresh_token' =>self::$refreshToken];
    }

    public function checkRefreshToken(){
        try{
            $refresh =   $this->tokenDecode(self::$refreshToken);
            if($this->getTSign() === $refresh['t_sign']){
                $cacheKey = $this->cachePrefix.$refresh['t_sign'];
                if(Cache::has($cacheKey)){
                    return Cache::get($cacheKey);
                }
            }
        }catch (TokenException $e){
        }

        return false;

    }



    /**
     * 生产accessToken
     * @param $data
     * @return string
     */
    private function accessTokenEncode($data){
        $time = time();
        $token = [
            "iss" => "",
            "aud" => "",
            "iat" => $time,
            "nbf" => $time,
            "exp" => $time + self::$tokenExpire
        ];

        self::$accessToken =  JWT::encode(array_merge($token,$data),$this->getSecretKey());
    }

    /**
     * 生产refreshToken
     * @param $data
     */
    private function refreshTokenEncode($data){
        $time = time();
        $expire = self::$tokenExpire * 2;
        $token = [
            "iss" => "",
            "aud" => "",
            "iat" => $time,
            "nbf" => $time,
            "exp" => $time + $expire,
            't_sign' => $this->getTSign()
        ];
        Cache::set($this->cachePrefix.$token['t_sign'],$data,$expire);
        self::$refreshToken =  JWT::encode($token,$this->getSecretKey());
    }


    private function tokenDecode($authorization){
        if(empty($authorization)){
            throw new TokenException('用户登录态无效',400);
        }
        try{
            $data = JWT::decode($authorization,$this->getSecretKey(),['HS256']);
        }catch (\Firebase\JWT\SignatureInvalidException $e) {
            throw new TokenException('用户登录态无效',400);
        } catch (\Firebase\JWT\ExpiredException $e) {
            throw new TokenException('用户登录态无效',401);
        } catch (\Exception $e) {
            throw new TokenException('用户登录态校验失败',400);
        }
        return (array)$data;
    }

    private function getTSign(){
        return  sha1(self::$accessToken.$this->getSecretKey());
    }








}